/*
 * PBoostMailBox.h
 *
 *  Created on: Jul 10, 2013
 *      Author: yuliang
 */

#ifndef PBOOSTMAILBOX_H_
#define PBOOSTMAILBOX_H_

#include <queue>
#include <stdint.h>
#include <boost/thread.hpp>

/*
 * @brief       消息邮箱类
 * @auther      lyl
 * @param [in]  M      : 消息邮件
 */
template<typename M>
class CBoostMailBox {
public:
	CBoostMailBox() {}
	virtual ~CBoostMailBox() {}

	/*
	 * @brief       发送消息邮件
	 * @auther      lyl
	 * @param [in]  mail   : 消息邮件
	 * @return      void
	 */
	void Send(const M& mail);

	/*
	 * @brief       接收消息邮件
	 * @auther      lyl
	 * @param [out] mail   : 消息邮件
	 * @return      bool   : false表示未接收到消息邮件,true表示接收到消息邮件
	 */
	bool Recv(M& mail);

	/*
	 * @brief       超时接收消息邮件
	 * @auther      lyl
	 * @param [out] mail   : 消息邮件
	 * @param [in]  msec   : 超时时间
	 * @return      bool   : false表示未接收到消息邮件,true表示接收到消息邮件
	 */
	bool TimeRecv(M& mail, uint32_t msec);

	/*
	 * @brief       清空消息邮件队列
	 * @auther      lyl
	 * @return      void
	 */
	void Clear();
private:
	CBoostMailBox(const CBoostMailBox&);
	const CBoostMailBox& operator=(const CBoostMailBox&);
private:
	std::queue<M> m_Mails;
	boost::mutex m_mutex;
	boost::condition_variable m_cond;
};

template<typename M>
void CBoostMailBox<M>::Send(const M& mail) {
	boost::mutex::scoped_lock lock(m_mutex);
	this->m_Mails.push(mail);
	if (1 <= m_Mails.size())
		this->m_cond.notify_all();
}

template<typename M>
bool CBoostMailBox<M>::Recv(M& mail) {
	boost::mutex::scoped_lock lock(m_mutex);
	while (this->m_Mails.empty()) {
		this->m_cond.wait(lock);
	}
	mail = this->m_Mails.front();
	this->m_Mails.pop();
	return true;
}

template<typename M>
bool CBoostMailBox<M>::TimeRecv(M& mail, uint32_t sec) {
	bool bFlag = false;

	boost::mutex::scoped_lock lock(m_mutex);
	while (this->m_Mails.empty()) {
		boost::posix_time::seconds const delay(sec);
		boost::system_time const start = boost::get_system_time();
		boost::system_time const timeout = start + delay;
		if (!this->m_cond.timed_wait(lock, timeout))
			goto GOTO;  // 超时
	}
	mail = this->m_Mails.front();
	this->m_Mails.pop();
	bFlag = true;
GOTO:
	return bFlag;
}

template<typename M>
void CBoostMailBox<M>::Clear() {
	boost::mutex::scoped_lock lock(m_mutex);
	while (!m_Mails.empty())
		m_Mails.pop();
}

#endif /* PBOOSTMAILBOX_H_ */
